/**
 *  @file commontypes.h
 *
 *  Contains some commonly used data types
 */

#ifndef _COMMONTYPES_H_
#define _COMMONTYPES_H_

/*
 *  For mingw only, since Cygwin and Linux GCC both have the '__SIZEOF_POINTER__' definition
 */
#if defined(__GNUC__) && !defined(__SIZEOF_POINTER__)
#  if defined(__MINGW64__)
#    define __SIZEOF_POINTER__ 8
#  elif defined(__MINGW32__)
#    define __SIZEOF_POINTER__ 4
#  endif
#endif


#if defined(WIN32)
   typedef __wchar_t wc_t;
#elif defined(linux)
   /*
    *  'wchar_t' is by default 4 bytes
    *  To make it comply with the '__wchar_t' on Windows, add the following switches:
    *
    *     -fwide-exec-charset=UTF-16LE  // to specify wide string constants are UTF-16 little endian
    *     -fshort-wchar                 // to make wchar_t to be 2 bytes
    */
   typedef wchar_t wc_t;
#endif

typedef unsigned char u8_t;
typedef unsigned short u16_t;
typedef unsigned int u32_t;


#if defined(WIN32)
   typedef __int64 i64_t;
   typedef unsigned __int64 u64_t;
#  define I64N(n) n##L
#  define U64N(n) n##L
#elif defined(linux)
   typedef long long i64_t;
   typedef unsigned long long u64_t;
#  define I64N(n) n##LL
#  define U64N(n) n##LLU
#endif


#if defined(__GNUC__)
#  if __SIZEOF_POINTER__ == 8
     typedef u64_t ptr_t;
#  elif __SIZEOF_POINTER__ == 4
     typedef u32_t ptr_t;
#  endif
#elif defined(_WIN64)
   typedef u64_t ptr_t;
#elif defined(WIN32)
   typedef u32_t ptr_t;
#endif


#if defined(__GNUC__)
#  if __SIZEOF_POINTER__ == 8
      typedef u64_t sz_t;
#  elif __SIZEOF_POINTER__ == 4
      typedef u32_t sz_t;
#  endif
#elif defined(_WIN64)
   typedef u64_t sz_t;
#elif defined(WIN32)
   typedef u32_t sz_t;
#endif


typedef int bool_t;

typedef wc_t* pwstr_t;
typedef const wc_t* pcwstr_t;

//! pointer to any object
typedef void* ptrany_t;

/**
 *  Standard C++ does not allow enum forward declaration because size of a enum is not
 *  determined until compiler has examined all values of a enum type. It can be a 'char'
 *  or a 'int' which depends on the greatest value.
 *
 *  For an ugly workaround, use enumforward_t to forward declare a enum type. In this way,
 *  the 'enum variable' will be the same size as 'sz_t'.
 */
typedef sz_t enumforward_t;

#ifndef NULL
#define NULL (0)
#endif

#ifndef TRUE
#define TRUE ((bool_t)1)
#endif

#ifndef FALSE
#define FALSE ((bool_t)0)
#endif

#define PRIVATE static
#define PUBLIC static

//! map the string to a wide char one
#if defined(UNICODE) || defined(_UNICODE)
#   define	_S(q) L##q
//! one more indirection if 'q' itself is a macro too
#   define	_U(q) (const wc_t*)_S(q)
#else 
#   define	_S(q) q
#   define	_U(q) _S(q)
#endif

#define STRINGIZE(num) _S(#num)
/**
 *  to convert an integer macros (num is itself a macro of an integer) to a string macro
 *
 *  e.g.
 *
 *  #define COUNT 10
 *  #define NUM2STR(COUNT)
 */
#define NUM2STR(num) STRINGIZE(num)

#include "ExportSymbols.h"

#endif
